package com.xiaoshuidi.cloud.module.report.xxljob;

import cn.hutool.core.util.IdcardUtil;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import com.xiaoshuidi.cloud.framework.tenant.core.aop.TenantIgnore;
import com.xiaoshuidi.cloud.module.report.constant.*;
import com.xiaoshuidi.cloud.module.report.dal.DO.*;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.ReportLedgerInfoDO;
import com.xiaoshuidi.cloud.module.report.dal.mapper.*;
import com.xiaoshuidi.cloud.module.report.dal.mapper.report.ReportLedgerInfoMapper;
import com.xiaoshuidi.cloud.module.report.utils.DateUtils;
import com.xiaoshuidi.cloud.module.report.xxljob.PO.ContractRentorderPO;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Period;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 台账信息数据job每天21:30点
 * 此处理后的数据供 在租台账，续租台账，转租台账，退租台账使用
 */
@Component
@Slf4j
public class ReportLedgerDataHandleJob {

    @Resource
    private ReportLedgerInfoMapper reportLedgerInfoMapper;
    @Resource
    private MemberUserMapper memberUserMapper;
    @Resource
    private ContractRentorderMapper contractRentorderMapper;
    @Resource
    private ContractOrderfeesMapper contractOrderfeesMapper;
    @Resource
    private ContractRoomMapper contractRoomMapper;
    @Resource
    private RoomHouseMapper roomHouseMapper;
    @Resource
    private  SystemDictDataMapper systemDictDataMapper;
    @Resource
    private ContractSettlementMapper contractSettlementMapper;
    @Resource
    private ContractSettlementDetailMapper contractSettlementDetailMapper;

    @XxlJob("reportLedgerDataHandleJob")
    @TenantIgnore
    public void execute() {
        //获取未处理的台账
        long totalNum = reportLedgerInfoMapper.countLedgerUnHandle();
        if(totalNum<=200){
            //合账数<100直接一次处理
            List<ReportLedgerInfoDO> list = reportLedgerInfoMapper.selectLedgerUnHandle();
            handleLedgerList(list);
        }else {
            //分200 一批次处理
            int pageNo = 0;
            int pageSize = 200;
            List<ReportLedgerInfoDO> list = Collections.emptyList();
            do {
                int from = pageNo*pageSize;
                list = reportLedgerInfoMapper.selectLedgerUnHandlePage(from,pageSize);
                handleLedgerList(list);
                pageNo++;
            }while (list.size()==200);
        }
    }

    /**
     * 填充相关数据到台账表，方便查询
     * @param list
     */
    private void handleLedgerList(List<ReportLedgerInfoDO> list){
        if(CollectionUtils.isEmpty(list)){
            return;
        }
        //获取字典表里的数据
        List<DictDataDO>  eduList = systemDictDataMapper.getDictMapByType(DictionaryEnum.EDUCATION.getCode());
        Map<String, String> eduMap = eduList.stream().collect(Collectors.toMap(DictDataDO::getValue, DictDataDO::getLabel));
        List<DictDataDO>  sourceList  = systemDictDataMapper.getDictMapByType(DictionaryEnum.SOURCE.getCode());
        Map<String, String> sourceMap = sourceList.stream().collect(Collectors.toMap(DictDataDO::getValue, DictDataDO::getLabel));

        //房源名称，年龄，性别，租赁期限，折扣后租金，已交租金，租金交至日期
        List<String> mobiles = list.stream().map(e -> e.getCustomerPhone()).collect(Collectors.toList());
        List<MemberUserDO> memberUserDOS = memberUserMapper.selectUserByMobiles(mobiles);

        for (ReportLedgerInfoDO infoDO : list) {
            if(ContractStatusEnum.NO_SIGNED.getStatus().equals(infoDO.getContractStatus())||ContractStatusEnum.PENDING.getStatus().equals(infoDO.getContractStatus())){
                //未签约的不处理
                continue;
            }
            try {
                if (!CollectionUtils.isEmpty(memberUserDOS)) {
                    memberUserDOS.forEach(e -> {
                        if (e.getMobile().equals(infoDO.getCustomerPhone())) {
                            infoDO.setAge(e.getAge());
                            infoDO.setGender(SexEnum.getValueByCode(e.getGender()));
                        }
                    });
                }
                //证件号码计算性别
                Integer gender = getGender(infoDO.getCustomerIdNumber());
                //1男0女
                if(gender!=null){
                    infoDO.setGender(1==gender.intValue()?"男":"女");
                }

                //计算折扣后租金 只针对周期性优惠的
                if ("cycle".equals(infoDO.getDiscountSort())) {
                    if ("rate".equals(infoDO.getDiscountType())) {
                        //按比例优惠
                        BigDecimal dicountValue = infoDO.getMonthRent().multiply(infoDO.getDiscountValue()).divide(BigDecimal.valueOf(100));
                        infoDO.setAfterDiscRent(infoDO.getMonthRent().subtract(dicountValue));
                    } else if ("amount".equals(infoDO.getDiscountType())) {
                        if(infoDO.getPayMethodF()!=null && infoDO.getPayMethodF()>0){
                            //按金额优惠
                            infoDO.setAfterDiscRent(infoDO.getMonthRent().subtract(infoDO.getDiscountValue().divide(BigDecimal.valueOf(infoDO.getPayMethodF()))));
                        }else{
                            infoDO.setAfterDiscRent(infoDO.getMonthRent().subtract(infoDO.getDiscountValue()));
                        }

                    }
                }
                //计算租赁期限(月)
//                infoDO.setLeaseTerm(DateUtils.getMonthSpace(infoDO.getStartTime(), infoDO.getEndTime()));
                //计算租赁期限考虑2月份数据偏移2天
                infoDO.setLeaseTerm(Period.between(infoDO.getStartTime(), infoDO.getEndTime().plusDays(2)).getMonths());
                //拼凑房源名称
                RoomHouseDO houseDO = roomHouseMapper.selectById(infoDO.getRoomId());
                if(houseDO ==null){
                    log.error("房源不应该为空 roomId:{}",infoDO.getRoomId());
                    continue;
                }
                //集中式和分散式拼凑方法不一样
                StringBuilder houseName = new StringBuilder(houseDO.getBuildingNo()).append("栋");
                if (houseDO.getIsConcentrated()) {
                    //集中式 小区名-楼栋-房源名称   room_house.area - room_house.building_no栋 - room_house.name
                    infoDO.setHouseResource(houseName.append(houseDO.getName()).toString());
                } else {
                    //分散式  小区名-楼栋-单元-房源名称 room_house.area - room_house.building_no栋 - room_house.unit_no单元 - room_house.name
                    infoDO.setHouseResource(houseName.append(houseDO.getUnitNo()).append("单元").append(houseDO.getName()).toString());
                }
                infoDO.setArea(houseDO.getArea());
                infoDO.setHandleFlag(1);

                //字典数据翻译
                infoDO.setPayWay(PayWayEnum.getValueByMonth(infoDO.getPayMethodF()));
                infoDO.setCustomerType(CustomTypeEnum.getValueByType(infoDO.getCustomerType()));
                infoDO.setCustomerEducation(eduMap.get(infoDO.getCustomerEducation()));
                infoDO.setSource(sourceMap.get(infoDO.getSource()));
                //TODO 如果此合同是续租 需处理续租的字段
                if (ContractNodeEnum.RENEWAL.getNode().equals(infoDO.getContractNode())) {
                    renewalDataProcess(infoDO);
                }
                //TODO 如果此合同是换租 需处理换租的字段
                if (ContractNodeEnum.EXCHANGE.getNode().equals(infoDO.getContractNode())) {
                    exChangeDataProcess(infoDO,list);
                }
                //TODO 如果此合同是退租 需处理退租的字段
                if (ContractStatusEnum.NORMAL_END.getStatus().equals(infoDO.getContractStatus()) || ContractStatusEnum.ABNORMAL_END.getStatus().equals(infoDO.getContractStatus())) {
                    rentingOutDataProcess(infoDO);
                }
            } catch (Exception e) {
                log.error("======处理台账跑批遇到异常====contractId:{}",infoDO.getContractId());
                e.printStackTrace();
            }
        }
        reportLedgerInfoMapper.updateBatch(list,list.size());
        reportLedgerInfoMapper.updateDeletedByStatus();
    }

    /**
     * 处理续租数据
     * @param infoDO
     */
    private void renewalDataProcess(ReportLedgerInfoDO infoDO){
        //需处理 续租时间（续租签约成功且首期账单支付时间）原合同起止日期,交房日期 第一份合同的交房时间，
        //查询续租合同第一笔账单支付时间
        ContractRentorderPO rentorderVO = contractRentorderMapper.selectFirstRenewalRentOrderByContractId(infoDO.getContractId());
        if(rentorderVO!=null && rentorderVO.getActualPayTime()!=null){
            infoDO.setNewContractDate(rentorderVO.getActualPayTime());
        }else {
            //如没有支付，则下次还需要job去查询支付时间
            infoDO.setHandleFlag(0);
        }
        //TODO 查询第一份合同的交房时间  读取第一次新签房间交割时间 alex
        ContractRoomDO contractRoomDO = contractRoomMapper.selectById(infoDO.getFromId());
        if(contractRoomDO==null){
            log.error("续租合同无上一份合同,续租合同id:{}",infoDO.getContractId());
            return;
        }
        infoDO.setOldStartTime(contractRoomDO.getStartTime());
        infoDO.setOldEndTime(contractRoomDO.getEndTime());
        while (contractRoomDO.getFromId() != null){
            contractRoomDO = contractRoomMapper.selectById(contractRoomDO.getFromId());
        }
        infoDO.setFirstContractDate(contractRoomDO.getStartTime());
    }

    /**
     * 处理换租数据
     * @param infoDO
     */
    private void exChangeDataProcess(ReportLedgerInfoDO infoDO,List<ReportLedgerInfoDO> list){
        ReportLedgerInfoDO infoDO1 = reportLedgerInfoMapper.selectByContractId(infoDO.getFromId());
        if(infoDO1 !=null){
//            infoDO.setOldStartTime(infoDO1.getStartTime());
//            infoDO.setOldEndTime(infoDO1.getEndTime());
            infoDO.setOldApartmentName(infoDO1.getApartmentName());
//            infoDO.setOldSignedTime(infoDO1.getSignedTime());
            if(infoDO1.getHouseResource()==null){
                ReportLedgerInfoDO reportLedgerInfoDO = list.stream().filter(e -> e.getContractId().equals(infoDO.getFromId())).findFirst().orElse(null);
                if(reportLedgerInfoDO!=null){
                    infoDO.setOldApartmentName(reportLedgerInfoDO.getApartmentName());
                    infoDO.setOldHouseResource(reportLedgerInfoDO.getHouseResource());
                    infoDO.setOldArea(reportLedgerInfoDO.getArea());
//                    infoDO.setOldSignedTime(reportLedgerInfoDO.getSignedTime());
                }
            }else {
                infoDO.setOldHouseResource(infoDO1.getHouseResource());
                infoDO.setOldArea(infoDO1.getArea());
            }
            //TODO 查询第一份合同的交房时间  读取第一次新签房间交割时间
            ContractRoomDO oldContractInfo = contractRoomMapper.selectById(infoDO.getFromId());
            infoDO.setOldStartTime(oldContractInfo.getStartTime());
            infoDO.setOldEndTime(oldContractInfo.getEndTime());
            infoDO.setOldSignedTime(oldContractInfo.getSignedTime());
            ContractRoomDO newContractInfo = contractRoomMapper.selectById(infoDO.getContractId());
            while (oldContractInfo.getFromId() != null){
                oldContractInfo = contractRoomMapper.selectById(oldContractInfo.getFromId());
            }
            infoDO.setFirstContractDate(oldContractInfo.getStartTime());
            infoDO.setExchangeDate(newContractInfo.getSignedTime());
            infoDO.setNewContractDate(newContractInfo.getCreateTime().toLocalDate());
        }
        //TODO  换租产生的费用是在结算单里
        List<ContractSettlementDO> settlementDOList = contractSettlementMapper.selectByContractId(infoDO.getContractId());
        if(!CollectionUtils.isEmpty(settlementDOList)){
            List<Long> settleIds = settlementDOList.stream().map(ContractSettlementDO::getId).collect(Collectors.toList());
            List<ContractSettlementDetailDO> settlementDetailDOS = contractSettlementDetailMapper.selectByOrderIds(settleIds);
            BigDecimal reduce = settlementDetailDOS.stream().map(ContractSettlementDetailDO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            infoDO.setExchangeAmount(reduce);
        }
    }

    /**
     * 处理退租数据
     * @param infoDO
     */
    private void rentingOutDataProcess(ReportLedgerInfoDO infoDO){
        try {
            //租赁期限(月)按实际退房时间
            infoDO.setLeaseTerm(DateUtils.getMonthSpace(infoDO.getStartTime(),infoDO.getActualEndTime()));
        } catch (Exception e) {
            log.error("退房没有记录退租时间，异常数据 contractId:{}",infoDO.getContractId());
        }
        //所交金额(含押金) 支付所有账单总金额，非退押金，退租扣除金额，扣除原因，
        //TODO 合同目前退租类型和退租原因取得是 EvictionTypeEnum code和msg 暂先统一改成msg
        infoDO.setEvictionType(infoDO.getEvictionReason());

        HashMap<Integer,BigDecimal> amountMap = contractRentorderMapper.selectTotalAmountByContractIdGroupByFlowType(infoDO.getContractId());//需咨询是否包含押金
        BigDecimal outAmount,inAmount;
        if(amountMap == null){
            outAmount=inAmount=BigDecimal.ZERO;
        }else {
            //流出
            outAmount = amountMap.get(1) == null?BigDecimal.ZERO:amountMap.get(1);
            //流入
            inAmount = amountMap.get(0)== null?BigDecimal.ZERO:amountMap.get(0);
        }
        infoDO.setOutTotalAmount(inAmount);
        //所退金额 退租合同账单 流出 且不含水电费
        //先查询退租合同对应的退租产生的账单 流出方向
        Long orderId = contractRentorderMapper.selectIdByContractIdOut(infoDO.getContractId());
        BigDecimal waterAndElecAmount = contractOrderfeesMapper.selectSumWaterAndElecByOrderId(orderId);
        waterAndElecAmount = waterAndElecAmount==null?BigDecimal.ZERO:waterAndElecAmount;
        infoDO.setOutDeductAmount(outAmount.subtract(waterAndElecAmount));
        BigDecimal depositByOrderId = contractOrderfeesMapper.selectDepositByOrderId(orderId);
//        infoDO.setNoRefundDeposit(infoDO.getDeposit().subtract(depositByOrderId == null?BigDecimal.ZERO:depositByOrderId));
        //TODO
        List<ContractSettlementDO> settlementDOList = contractSettlementMapper.selectByContractId(infoDO.getContractId());
        if(!CollectionUtils.isEmpty(settlementDOList)){
            List<Long> settleIds = settlementDOList.stream().filter(e->"out".equals(e.getFlowType())).map(ContractSettlementDO::getId).collect(Collectors.toList());
            List<ContractSettlementDetailDO> settlementDetailDOS = contractSettlementDetailMapper.selectByOrderIds(settleIds);
            BigDecimal reduce = settlementDetailDOS.stream().filter(e->e.getRefundableAmount()!=null&&"out".equals(e.getFlowType())).map(ContractSettlementDetailDO::getRefundableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal deposit =settlementDetailDOS.stream().filter(e->"押金".equals(e.getFeeName())&&"out".equals(e.getFlowType())).map(ContractSettlementDetailDO::getRefundableAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            infoDO.setRentingOutAmount(reduce.negate());
            infoDO.setNoRefundDeposit(infoDO.getDeposit().subtract(deposit == null?BigDecimal.ZERO:deposit));
        }
    }

    /**
     * 获取性别
     * @param idNumber
     * @return
     */
    private  Integer getGender(String idNumber) {
        String customerIdNumber = StrUtil.isNotBlank(idNumber)? idNumber.replaceAll("\\s", ""):null;
        Integer gender = null;
        //年龄计算
        if(StrUtil.isNotBlank(customerIdNumber)){
            try {
                gender = IdcardUtil.getGenderByIdCard(customerIdNumber);
            } catch (Exception ex) {
            }
        }
        return gender;
    }

    public static void main(String[] args) {
        int months = Period.between(LocalDate.parse(  "2023-06-30"), LocalDate.parse( "2024-02-28").plusDays( 2)).getMonths();
        System.out.println(months);
        int months1 = Period.between(LocalDate.parse(  "2023-06-30"), LocalDate.parse( "2024-02-29")).getMonths();
        System.out.println(months1);
    }
}
